-- Author: shineflag
-- Date: 2017-08-11 14:46:43
--
--机器人的ai策略库 
local tl = require("texas_ailib")
local log = require("log")

local texas_ai = {}
local texas_ai_meta = {
	__index = texas_ai 
}
local robot_ai = {}

local CARD_FACE_TWO      = 0x02
local CARD_FACE_THERR    = 0x03
local CARD_FACE_FOUR     = 0x04
local CARD_FACE_FIVE     = 0x05
local CARD_FACE_SIX      = 0x06
local CARD_FACE_SEVEN    = 0x07
local CARD_FACE_EIGHT    = 0x08
local CARD_FACE_NINE     = 0x09
local CARD_FACE_TEN      = 0x0A
local CARD_FACE_JACK 	 = 0x0B
local CARD_FACE_QUEEN    = 0x0C
local CARD_FACE_KING     = 0x0D
local CARD_FACE_ACE      = 0x0E

local CARD_SUIT_DIAMOND 	= 0x00  --方片
local CARD_SUIT_CLUB 		= 0x10  --梅花
local CARD_SUIT_HEART 		= 0x20  --红桃
local CARD_SUIT_SPADE 		= 0x30  --黑桃

local kHighCard = 1
local kOnePair = 2
local kTwoPair = 3
local kThreeKind = 4
local kStraight = 5
local kFlush = 6
local kFullHouse = 7
local kKingKong = 8
local kFlushStraight = 9
local kRoyalFlush = 10


--game status 游戏的状态
local status = {
	idle      = -1,  --空闲阶段
	wait      = 0,   --准备开始
	preflop   = 1,   --发手牌的第一轮行动
	flop      = 2,   --翻三张牌
	turn      = 3,   --转牌
	river     = 4,   --河牌
	over      = 5,   --结算时间
}

local thands = {
	pair = 1,       --手牌对
	sflush = 2,     --手牌同花顺
	flush = 3,      --手牌同花
	straight = 4,   --手牌顺
	high = 5,       --手牌杂
}

local opts = {
	fold = 0, --弃牌
	bet = 1   --下注
}

--起始手牌的 弃 跟 加 概率  ?/10000
local pre_hands = {  
	[thands.pair]     = {fold= 1000, check=3000, raise=6000},
	[thands.sflush]   = {fold= 2000, check=4000, raise=4000},
	[thands.flush]    = {fold= 3000, check=4000, raise=3000},
	[thands.straight] = {fold= 3000, check=4000, raise=3000},
	[thands.high]     = {fold= 5000, check=3000, raise=2000},
}

local ctype_st = {

	[kHighCard]      = {fold= 6000, check=5000, raise=1000},
	[kOnePair]       = {fold= 5000, check=4000, raise=1000},
	[kTwoPair]       = {fold= 3000, check=4000, raise=3000},
	[kThreeKind]     = {fold= 2000, check=5000, raise=3000},
	[kStraight]      = {fold= 2000, check=4000, raise=4000},
	[kFlush]         = {fold= 2000, check=3000, raise=5000},
	[kFullHouse]     = {fold= 1000, check=4000, raise=5000},
	[kKingKong]      = {fold= 1000, check=2000, raise=7000},
	[kFlushStraight] = {fold= 1000, check=1000, raise=8000},
	[kRoyalFlush]    = {fold= 1000, check=1000, raise=8000},
}

--检查概率表的值
local function check_strategy(st)
	local sum = 0 
	for key, val in pairs(st) do 
		if val < 0 then 
			st[key] = 0
		end
		sum = sum + st[key]
	end
	return sum 
end

function robot_ai.new()
	local c = {
		sinfo_ = {},  --自己的座位的信息 @see robot_agent.lua set_seat_info
		rinfo_ = {},  --房间的信息 @see robot_agent.lua texas_init
	}
	math.randomseed(os.time())
	return setmetatable(c, texas_ai_meta)
end


function texas_ai:_preflopaction(data)
	local ht = tl.hands_patterns(self.sinfo_.cards)

	--最大做成 13x13x4 t[ht][card1][card2]
	local strategy = pre_hands[ht]

	--先做简单的
	local f  = {tl.face(self.sinfo_.cards[1]),tl.face(self.sinfo_.cards[2]) }
	local s =  {tl.suit(self.sinfo_.cards[1]),tl.suit(self.sinfo_.cards[2]) }
	if ht == thands.pair then
		--起手对A 必加注
		if f[1] == CARD_FACE_ACE then 
			strategy.fold = 0
			strategy.check = 0 
			strategy.raise = 10000 
		elseif f[1] > CARD_FACE_NINE then
			--对10上的越大，加注越高
			strategy.check = strategy.check + 1000 * (f[1]-CARD_FACE_NINE)
		end
	elseif ht ==  thands.sflush or ht == thands.straight then 
		if f[2] > CARD_FACE_NINE then
			--10上的越大，加注概率越高
			strategy.check = strategy.check + 800 * (f[2]-CARD_FACE_NINE)
			strategy.raise = strategy.raise + 800 * (f[2]-CARD_FACE_NINE)
		elseif f[1] < CARD_FACE_NINE then
			--顺面越小 弃牌和跟注的概率越高
			strategy.fold = strategy.fold + 1000 * (CARD_FACE_NINE-f[1])
			strategy.check = strategy.check + 300 * (CARD_FACE_NINE-f[1])
		end
	elseif ht ==  thands.flush or ht == thands.high then 
		if f[2] > CARD_FACE_NINE then
			--10上的越大，加注概率越高
			strategy.check = strategy.check + 200 * (f[2]-CARD_FACE_NINE)
			strategy.fold = strategy.fold + 400 * (CARD_FACE_NINE-f[2])
		elseif f[2] < CARD_FACE_NINE then
			--顺面越小 弃牌和跟注的概率越高
			strategy.fold = strategy.fold + 200 * (CARD_FACE_NINE-f[2])
			strategy.check = strategy.check + 200 * (CARD_FACE_NINE-f[2])
		end
	end
	
	local total = check_strategy(strategy) 

	local num = math.random(total)
	log.d(TAG,"ht[%d] fold[%d] check[%d] raise[%d] total[%d] num[%d]",ht,strategy.fold, strategy.check, strategy.raise, total, num)
	if num < strategy.fold then 
		--无需下注的时候不能弃牌
		if data.check == 0 then 
			return opts.bet, 0 
		elseif self.sng_mode_ and self.sinfo_.rchips > 0 and self.sinfo_.coin < self.rinfo_.bb * 3 then
			--小于3BB且已下了注的，要ALL in
			return opts.bet, data.raisemax
		else
			return opts.fold, 0 
		end
	elseif num < strategy.fold + strategy.check then
		local check_coin = data.check > data.raisemax and data.raisemax or data.check
		if self.sng_mode_ and self.sinfo_.rchips > 0 and self.sinfo_.coin < self.rinfo_.bb * 3 then
			--小于3BB且已下了注的，要ALL in
			check_coin =  data.raisemax
		end
		return opts.bet, check_coin
	else
		local pot = self.rinfo_.tpot
		local times = math.random(2)

		local rcoin = math.ceil(pot/times)
		if rcoin < data.raisemin then 
			rcoin = data.raisemin
		end
		if rcoin > data.raisemax then 
			rcoin = data.raisemax 
		end

		if self.sng_mode_  and self.sinfo_.coin < self.rinfo_.bb * 3 then
			--小于3BB且要加注的，要ALL in
			rcoin =  data.raisemax
		end

		return opts.bet, rcoin
	end
end

function texas_ai:_flopaction(data)

	local ctype, bcards = tl.make_cards(self.rinfo_.public_cards, self.sinfo_.cards)
	local ht = tl.hands_patterns(self.sinfo_.cards)

	local strategy = ctype_st[ctype]

	--先做简单的
	local f  = {tl.face(self.sinfo_.cards[1]),tl.face(self.sinfo_.cards[2]) }
	local s =  {tl.suit(self.sinfo_.cards[1]),tl.suit(self.sinfo_.cards[2]) }

	if ht == thands.pair then
		--起手对A 必加注
		if ctype == kKingKong or ctype == kFullHouse then 
			strategy.fold = 0 
			strategy.check = 0
		else
			--最高口袋对
			if f[1] > tl.face(bcards[3]) then 
				strategy.fold = 0 
				strategy.check = 0
			else
				if f[1] > CARD_FACE_NINE then
					--对10上的越大，加注越高
					strategy.raise = strategy.raise + 1000 * (f[1]-CARD_FACE_NINE)
				end
			end

		end

	elseif ht ==  thands.sflush  then 
		if ctype == kFlushStraight or ctype == kRoyalFlush then 
			strategy.fold = 0 
			strategy.check = 0
		elseif ctype == kStraight  then 
			--最大顺子 或 
			if f[1] == tl.face(bcards[1])  then 
				strategy.fold = 0 
				strategy.check = 0
			end 
			strategy.raise = strategy.raise + 1000 * (f[1]-CARD_FACE_TEN)
		end
	elseif ht == thands.straight then 
		if ctype == kStraight then 
			strategy.fold = 0 
			strategy.check = 0
		end
	elseif ht ==  thands.flush then 
		if ctype == kFlush then 
			strategy.fold = 0 
			strategy.check = 0
		end
	elseif ht == thands.high then 
		if f[1] > CARD_FACE_QUEEN then
			--10上的越大，加注概率越高
			strategy.check = strategy.check + 200 * (f[1]-CARD_FACE_QUEEN)
		elseif f[2] < CARD_FACE_NINE then
			--顺面越小 弃牌和跟注的概率越高
			strategy.fold = strategy.fold + 200 * (CARD_FACE_NINE-f[2])
		end
	end

	if ctype > kOnePair  then 
		local traise = (ctype - kHighCard) * 600
		local fraise = (f[2]-CARD_FACE_NINE) * 200 
		local fcheck = (f[1]-CARD_FACE_NINE) * 200 
		local ffold =  (CARD_FACE_NINE - f[1]) * 300

		strategy.raise = strategy.raise + traise + fraise
		strategy.check = strategy.check + fcheck
		--strategy.fold  = strategy.fold + ffold
	else
		local ffold =  (CARD_FACE_QUEEN - f[1]) * 400
		local fcheck = (f[2]-CARD_FACE_NINE) * 200 
		strategy.check = strategy.check + fcheck
		strategy.fold  = strategy.fold + ffold
	end

	local total = check_strategy(strategy)

	local num = math.random(total)

	log.d(TAG,"gs[%d] pcards[%s] hands[%s] ctype[%d] bcards[%s]",
		self.rinfo_.gamestatus, tl.cards_str(self.rinfo_.public_cards),
		tl.cards_str(self.sinfo_.cards), ctype, tl.cards_str(bcards) )
	log.d(TAG,"ht[%d] fold[%d] check[%d] raise[%d] total[%d] num[%d]",ht,strategy.fold, strategy.check, strategy.raise, total, num)
	if num < strategy.fold then 
		--无需下注的时候不能弃牌
		if data.check == 0 then 
			return opts.bet, 0 
		else
			return opts.fold, 0 
		end
	elseif num < strategy.fold + strategy.check then
		local check_coin = data.check > data.raisemax and data.raisemax or data.check
		return opts.bet, check_coin
	else
		local pot = self.rinfo_.tpot
		local times = math.random(2)

		local rcoin = math.ceil(pot/times)
		if rcoin < data.raisemin then 
			rcoin = data.raisemin
		end
		if rcoin > data.raisemax then 
			rcoin = data.raisemax 
		end

		return opts.bet, rcoin
	end
end

function texas_ai:_turnaction(data)
	local ctype, bcards = tl.make_cards(self.rinfo_.public_cards, self.sinfo_.cards)
	local ht = tl.hands_patterns(self.sinfo_.cards)

	local strategy = ctype_st[ctype]

	--先做简单的
	local f  = {tl.face(self.sinfo_.cards[1]),tl.face(self.sinfo_.cards[2]) }
	local s =  {tl.suit(self.sinfo_.cards[1]),tl.suit(self.sinfo_.cards[2]) }

	if ht == thands.pair then
		--起手对A 必加注
		if ctype == kKingKong or ctype == kFullHouse then 
			strategy.fold = 0 
			strategy.check = 0
		else
			--最高口袋对
			if f[1] > tl.face(bcards[3]) then 
				strategy.fold = 0 
				strategy.check = 0
			else
				if f[1] > CARD_FACE_NINE then
					--对10上的越大，加注越高
					strategy.raise = strategy.raise + 1000 * (f[1]-CARD_FACE_NINE)
				end
			end

		end

	elseif ht ==  thands.sflush  then 
		if ctype == kFlushStraight or ctype == kRoyalFlush then
			strategy.fold = 0 
			strategy.check = 0
		elseif ctype == kStraight  then 
			--最大顺子 或 
			if f[1] == tl.face(bcards[1])  then 
				strategy.fold = 0 
				strategy.check = 0
			end 
			strategy.raise = strategy.raise + 1000 * (f[1]-CARD_FACE_TEN)
		end
	elseif ht == thands.straight then 
		if ctype == kStraight then 
			strategy.fold = 0 
			strategy.check = 0
		end
	elseif ht ==  thands.flush then 
		if ctype == kFlush then 
			strategy.fold = 0 
			strategy.check = 0
		end
	elseif ht == thands.high then 
		if f[1] > CARD_FACE_QUEEN then
			--10上的越大，加注概率越高
			strategy.check = strategy.check + 200 * (f[1]-CARD_FACE_QUEEN)
		elseif f[2] < CARD_FACE_NINE then
			--顺面越小 弃牌和跟注的概率越高
			strategy.fold = strategy.fold + 200 * (CARD_FACE_NINE-f[2])
		end
	end

	if ctype > kOnePair  then 
		local traise = (ctype - kHighCard) * 600
		local fraise = (f[2]-CARD_FACE_NINE) * 200 
		local fcheck = (f[1]-CARD_FACE_NINE) * 200 
		local ffold =  (CARD_FACE_NINE - f[1]) * 100

		strategy.raise = strategy.raise + traise + fraise
		strategy.check = strategy.check + fcheck
		strategy.fold  = strategy.fold + ffold
	else
		local ffold =  (CARD_FACE_QUEEN - f[1]) * 200
		local fcheck = (f[2]-CARD_FACE_NINE) * 200 
		strategy.check = strategy.check + fcheck
		strategy.fold  = strategy.fold + ffold
	end

	local total = check_strategy(strategy)

	local num = math.random(total)
	log.d(TAG,"gs[%d] pcards[%s] hands[%s] ctype[%d] bcards[%s]",
		self.rinfo_.gamestatus, tl.cards_str(self.rinfo_.public_cards),
		tl.cards_str(self.sinfo_.cards), ctype, tl.cards_str(bcards) )
	log.d(TAG,"ht[%d] fold[%d] check[%d] raise[%d] total[%d] num[%d]",ht,strategy.fold, strategy.check, strategy.raise, total, num)
	if num < strategy.fold then 
		--无需下注的时候不能弃牌
		if data.check == 0 then 
			return opts.bet, 0 
		else
			return opts.fold, 0 
		end
	elseif num < strategy.fold + strategy.check then
		local check_coin = data.check > data.raisemax and data.raisemax or data.check
		return opts.bet, check_coin
	else
		local pot = self.rinfo_.tpot
		local times = math.random(2)

		local rcoin = math.ceil(pot/times)
		if rcoin < data.raisemin then 
			rcoin = data.raisemin
		end
		if rcoin > data.raisemax then 
			rcoin = data.raisemax 
		end

		return opts.bet, rcoin
	end
end

function texas_ai:_riveraction(data)
	local ctype, bcards = tl.make_cards(self.rinfo_.public_cards, self.sinfo_.cards)
	local ht = tl.hands_patterns(self.sinfo_.cards)

	local strategy = ctype_st[ctype]

	--先做简单的
	local f  = {tl.face(self.sinfo_.cards[1]),tl.face(self.sinfo_.cards[2]) }
	local s =  {tl.suit(self.sinfo_.cards[1]),tl.suit(self.sinfo_.cards[2]) }

	if ht == thands.pair then
		--起手对A 必加注
		if ctype == kKingKong or ctype == kFullHouse then 
			strategy.fold = 0 
			strategy.check = 0
		else
			--最高口袋对
			if f[1] > tl.face(bcards[3]) then 
				strategy.fold = 0 
				strategy.check = 0
			else
				if f[1] > CARD_FACE_NINE then
					--对10上的越大，加注越高
					strategy.raise = strategy.raise + 1000 * (f[1]-CARD_FACE_NINE)
				end
			end

		end

	elseif ht ==  thands.sflush  then 
		if ctype == kFlushStraight or ctype == kRoyalFlush then
			strategy.fold = 0 
			strategy.check = 0
		elseif ctype == kStraight  then 
			--最大顺子 或 
			if f[1] == tl.face(bcards[1])  then 
				strategy.fold = 0 
				strategy.check = 0
			end 
			strategy.raise = strategy.raise + 1000 * (f[1]-CARD_FACE_TEN)
		end
	elseif ht == thands.straight then 
		if ctype == kStraight then 
			strategy.fold = 0 
			strategy.check = 0
		end
	elseif ht ==  thands.flush then 
		if ctype == kFlush then 
			strategy.fold = 0 
			strategy.check = 0
		end
	elseif ht == thands.high then 
		if f[1] > CARD_FACE_QUEEN then
			--10上的越大，加注概率越高
			strategy.check = strategy.check + 200 * (f[1]-CARD_FACE_QUEEN)
		elseif f[2] < CARD_FACE_NINE then
			--顺面越小 弃牌和跟注的概率越高
			strategy.fold = strategy.fold + 200 * (CARD_FACE_NINE-f[2])
		end
	end

	if ctype > kOnePair  then 
		local traise = (ctype - kHighCard) * 600
		local fraise = (f[2]-CARD_FACE_NINE) * 200 
		local fcheck = (f[1]-CARD_FACE_NINE) * 200 
		local ffold =  (CARD_FACE_NINE - f[1]) * 100

		strategy.raise = strategy.raise + traise + fraise
		strategy.check = strategy.check + fcheck
		strategy.fold  = strategy.fold + ffold
	else
		local ffold =  (CARD_FACE_QUEEN - f[1]) * 400
		local fcheck = (f[2]-CARD_FACE_NINE) * 200 
		strategy.check = strategy.check + fcheck
		strategy.fold  = strategy.fold + ffold
	end

	local total = check_strategy(strategy)

	local num = math.random(total)
	log.d(TAG,"gs[%d] pcards[%s] hands[%s] ctype[%d] bcards[%s]",
		self.rinfo_.gamestatus, tl.cards_str(self.rinfo_.public_cards),
		tl.cards_str(self.sinfo_.cards), ctype, tl.cards_str(bcards) )
	log.d(TAG,"ht[%d] fold[%d] check[%d] raise[%d] total[%d] num[%d]",ht,strategy.fold, strategy.check, strategy.raise, total, num)
	if num < strategy.fold then 
		--无需下注的时候不能弃牌
		if data.check == 0 then 
			return opts.bet, 0 
		else
			return opts.fold, 0 
		end
	elseif num < strategy.fold + strategy.check then
		local check_coin = data.check > data.raisemax and data.raisemax or data.check
		return opts.bet, check_coin
	else
		local pot = self.rinfo_.tpot
		local times = math.random(2)

		local rcoin = math.ceil(pot/times)
		if rcoin < data.raisemin then 
			rcoin = data.raisemin
		end
		if rcoin > data.raisemax then 
			rcoin = data.raisemax 
		end

		return opts.bet, rcoin
	end
end


--设置ai房间的信息
function texas_ai:set_room(rinfo, sng_mode)
	self.rinfo_ = rinfo 
	self.sng_mode_ = sng_mode
end

function texas_ai:set_sinfo(sinfo)
	self.sinfo_ = sinfo
end

function texas_ai:action( data )
	if self.rinfo_.gamestatus == status.preflop then 
		return self:_preflopaction(data)
	elseif self.rinfo_.gamestatus == status.flop then 
		return self:_flopaction(data)
	elseif self.rinfo_.gamestatus == status.turn then 
		return self:_turnaction(data)
	elseif self.rinfo_.gamestatus == status.river then 
		return self:_riveraction(data)
	end
end

return robot_ai

